package com.yike.user.scheduled;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.yike.common.tool.DateUtil;
import com.yike.user.entity.*;
import com.yike.user.mapper.*;
import com.yike.user.vo.AgentCountDataVo;
import com.yike.user.vo.ShopTransactionDataVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;

/**
 * @author Sakura
 * @date 2024/9/9 11:24
 */
@Component
@EnableScheduling
@Slf4j
public class ScheduledCommission {

    @Autowired
    private ShopMapper shopMapper;
    @Autowired
    private AgentMapper agentMapper;
    @Autowired
    private AgentShopMapper agentShopMapper;
    @Autowired
    private CommissionSettleMapper commissionSettleMapper;
    @Autowired
    private AgentCommissionMapper agentCommissionMapper;
    @Autowired
    private ShopCountMapper shopCountMapper;
    @Autowired
    private AgentCountMapper agentCountMapper;
    @Autowired
    private AgentShopCountMapper agentShopCountMapper;

    /**
     * @description: 每天凌晨开始统计代理商分润
     * @author: Sakura
     * @date: 2024/9/9 11:27
     */
    @Scheduled(cron = "0 30 0 * * ?") // 0 0 0 * * ? 每天0点30启动
    //@Scheduled(initialDelay = 30000, fixedRate = Long.MAX_VALUE) // 测试用
    @Async
    @Transactional
    public void agentCommissionCount() {
        log.info("代理商分润统计程序启动——————————————————————————————————————————");
        // 获取前一天每个店铺的交易金额
        // 获取昨天的日期
        LocalDate yesterday = LocalDate.now().minusDays(1);
        // 定义日期格式
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        // 将日期格式化为字符串
        String strYesterday = yesterday.format(formatter);
        List<ShopTransactionDataVo> shopTransactionDataVos = shopMapper.getShopTransactionData(null, strYesterday, null, null);
        log.info(strYesterday + " 交易数据 " + JSON.toJSONString(shopTransactionDataVos));
        for (ShopTransactionDataVo shopTransactionDataVo : shopTransactionDataVos) {
            // 获取店铺信息和对应的商家信息，得到平台分润
            Shop shop = shopMapper.selectById(shopTransactionDataVo.getShopId());
            if (shop != null && shop.getMerchantId() != null) {
                ShopCount shopCount = shopCountMapper.selectOne(Wrappers.lambdaQuery(ShopCount.class)
                        .eq(ShopCount::getShopId, shop.getId())
                        .eq(ShopCount::getCountDate, strYesterday));
                if (shopCount == null) {
                    shopCount = new ShopCount();
                    shopCount.setShopId(shop.getId());
                    shopCount.setCountDate(DateUtil.parse(strYesterday, "yyyy-MM-dd"));
                    shopCount.setCommissionAmount(new BigDecimal("0"));
                    shopCount.setTotalAmount(new BigDecimal("0"));
                    shopCount.setActualAmount(new BigDecimal("0"));
                    shopCount.setWxAmount(new BigDecimal("0"));
                    shopCount.setAliAmount(new BigDecimal("0"));
                    shopCount.setOrderNumber(0);
                    shopCount.setRefundNumber(0);
                    shopCount.setWxOrderNumber(0);
                    shopCount.setAliOrderNumber(0);

                    shopCountMapper.insert(shopCount);
                }

                // 防止费率发送更改此处需要重新set一次
                shopCount.setCommissionRate(shop.getCommissionRate());
                shopCount.setOrderNumber(shopTransactionDataVo.getOrderNumber());
                shopCount.setTotalAmount(shopTransactionDataVo.getTotalAmount());
                shopCount.setActualAmount(shopTransactionDataVo.getActualAmount());
                shopCount.setCommissionRate(shop.getCommissionRate());
                BigDecimal shopCommission = shopCount.getActualAmount().multiply(shop.getCommissionRate()).divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP);
                shopCount.setCommissionAmount(shopCommission);

                shopCountMapper.updateById(shopCount);

                // 获取店铺代理商信息计算代理商费率
                AgentShop agentShop = agentShopMapper.selectOne(Wrappers.lambdaQuery(AgentShop.class)
                        .eq(AgentShop::getShopId, shop.getId()));
                if (agentShop != null) {
                    // 获取代理商信息
                    Agent agent = agentMapper.selectById(agentShop.getAgentId());
                    if (agent != null && agent.getCommissionRate() != null) {
                        // 计算当前代理商分润，分润是百分比需要转换
                        BigDecimal agentCommission = shopCount.getActualAmount().multiply(agent.getCommissionRate()).divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP);

                        AgentShopCount agentShopCount = agentShopCountMapper.selectOne(Wrappers.lambdaQuery(AgentShopCount.class)
                                .eq(AgentShopCount::getAgentId, agent.getId())
                                .eq(AgentShopCount::getShopCountId, shopCount.getId()));
                        if (agentShopCount == null) {
                            agentShopCount = new AgentShopCount();
                            agentShopCount.setShopCountId(shopCount.getId());
                            agentShopCount.setAgentId(agent.getId());
                            agentShopCountMapper.insert(agentShopCount);
                        }

                        agentShopCount.setParentFlag(false);
                        agentShopCount.setCommissionAmount(agentCommission);
                        agentShopCount.setCommissionRate(agent.getCommissionRate());
                        agentShopCountMapper.updateById(agentShopCount);
                        // 如果parentId不为0则说明还有上级代理商，上级代理商也需要分润
                        if (agent.getParentId() != 0) {
                            // 获取上级代理商信息
                            Agent parentAgent = agentMapper.selectById(agent.getParentId());
                            if (parentAgent != null && parentAgent.getCommissionRate() != null) {
                                // 这里要注意上级代理的分润是需要扣除下级的分润的，所以上级的比例必须大于下级才可以进行分润
                                if (parentAgent.getCommissionRate().compareTo(agent.getCommissionRate()) > 0) {
                                    // 计算上级代理商分润
                                    BigDecimal parentRate = parentAgent.getCommissionRate().subtract(agent.getCommissionRate());
                                    BigDecimal parentCommission = shopCount.getActualAmount().multiply(parentRate).divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP);

                                    AgentShopCount parentAgentShopCount = agentShopCountMapper.selectOne(Wrappers.lambdaQuery(AgentShopCount.class)
                                            .eq(AgentShopCount::getAgentId, parentAgent.getId())
                                            .eq(AgentShopCount::getShopCountId, shopCount.getId()));
                                    if (parentAgentShopCount == null) {
                                        parentAgentShopCount = new AgentShopCount();
                                        parentAgentShopCount.setShopCountId(shopCount.getId());
                                        parentAgentShopCount.setAgentId(parentAgent.getId());
                                        agentShopCountMapper.insert(parentAgentShopCount);
                                    }

                                    parentAgentShopCount.setParentFlag(true);
                                    parentAgentShopCount.setCommissionAmount(parentCommission);
                                    parentAgentShopCount.setCommissionRate(parentRate);
                                    agentShopCountMapper.updateById(parentAgentShopCount);
                                } else {
                                    log.info(parentAgent.getId() + " 父代理商分润信息异常++++++");
                                }
                            } else {
                                log.info(agent.getId() + " 父代理商信息异常++++++");
                            }
                        }
                    } else {
                        log.info(shop.getId() + " 代理商信息异常++++++");
                    }
                } else {
                    log.info(shop.getId() + " 店铺信息异常++++++");
                }
            } else {
                log.info(shopTransactionDataVo.getShopId() + " 所在店铺信息异常++++++");
            }
        }

        // 重新汇总一遍代理商统计数据
        List<AgentCountDataVo> agentCountDataVos = agentShopCountMapper.getAgentCountDataVos(strYesterday);
        for (AgentCountDataVo agentCountDataVo : agentCountDataVos) {
            // 汇总代理商分润，因为一个代理商可能有很多店铺
            AgentCount agentCount = agentCountMapper.selectOne(Wrappers.lambdaQuery(AgentCount.class)
                    .eq(AgentCount::getAgentId, agentCountDataVo.getAgentId())
                    .eq(AgentCount::getCountDate, strYesterday));
            if (agentCount == null) {
                agentCount = new AgentCount();
                agentCount.setAgentId(agentCountDataVo.getAgentId());
                agentCount.setCountDate(DateUtil.parse(strYesterday, "yyyy-MM-dd"));
                agentCountMapper.insert(agentCount);
            }
            agentCount.setCommissionAmount(agentCountDataVo.getCommissionAmount());
            agentCount.setTotalAmount(agentCountDataVo.getTotalAmount());
            agentCount.setActualAmount(agentCountDataVo.getActualAmount());
            agentCountMapper.updateById(agentCount);
        }
    }

    /**
     * @description: 每天凌晨开始统计代理商分润结算（结算7天前的统计）
     * @author: Sakura
     * @date: 2024/9/9 11:27
     */
    @Scheduled(cron = "0 0 2 * * ?") // 0 0 0 * * ? 每天2点启动
    //@Scheduled(initialDelay = 30000, fixedRate = Long.MAX_VALUE) // 测试用
    @Async
    @Transactional
    public void agentCommissionSettle() {
        log.info("代理商分润结算程序启动——————————————————————————————————————————");
        // 获取七天前未结算的统计数据
        String dateStr = DateUtil.format(LocalDate.now().minusDays(7), "yyyy-MM-dd");
        List<AgentCount> agentCounts = agentCountMapper.selectList(Wrappers.lambdaQuery(AgentCount.class)
                .eq(AgentCount::getStatus, 0)
                .le(AgentCount::getCountDate, dateStr));
        for (AgentCount agentCount : agentCounts) {
            // 设置结算状态
            agentCount.setStatus(1);
            agentCountMapper.updateById(agentCount);
            // 将数据结算到新的表格
            CommissionSettle commissionSettle = commissionSettleMapper.selectOne(Wrappers.lambdaQuery(CommissionSettle.class)
                    .eq(CommissionSettle::getAgentId, agentCount.getAgentId())
                    .eq(CommissionSettle::getSettleDate, dateStr));
            if (commissionSettle == null) {
                commissionSettle = new CommissionSettle();
                commissionSettle.setAgentId(agentCount.getAgentId());
                commissionSettle.setSettleDate(DateUtil.parse(dateStr, "yyyy-MM-dd"));
                commissionSettle.setAmount(agentCount.getCommissionAmount());
                commissionSettleMapper.insert(commissionSettle);
            } else {
                commissionSettle.setAmount(commissionSettle.getAmount().add(agentCount.getCommissionAmount()));
                commissionSettle.setUpdateTime(new Date());
                commissionSettleMapper.updateById(commissionSettle);
            }
            // 结算后需要增加代理商提现金额
            AgentCommission agentCommission = agentCommissionMapper.selectOne(Wrappers.lambdaQuery(AgentCommission.class)
                    .eq(AgentCommission::getAgentId, agentCount.getAgentId()));
            if (agentCommission == null) {
                agentCommission = new AgentCommission();
                agentCommission.setAgentId(agentCount.getAgentId());
                agentCommission.setTotalAmount(agentCount.getCommissionAmount());
                agentCommission.setWithdrawableAmount(agentCount.getCommissionAmount());
                agentCommissionMapper.insert(agentCommission);
            } else {
                agentCommission.setTotalAmount(agentCommission.getTotalAmount().add(agentCount.getCommissionAmount()));
                agentCommission.setWithdrawableAmount(agentCommission.getWithdrawableAmount().add(agentCount.getCommissionAmount()));
                agentCommission.setUpdateTime(new Date());
                agentCommissionMapper.updateById(agentCommission);
            }
        }
    }
}
